package plp.orientadaObjetos2.expressao.unaria;

import plp.expressions2.memory.VariavelJaDeclaradaException;
import plp.expressions2.memory.VariavelNaoDeclaradaException;
import plp.orientadaObjetos1.excecao.declaracao.ClasseNaoDeclaradaException;
import plp.orientadaObjetos1.excecao.declaracao.ObjetoJaDeclaradoException;
import plp.orientadaObjetos1.excecao.declaracao.ObjetoNaoDeclaradoException;
import plp.orientadaObjetos1.expressao.Expressao;
import plp.orientadaObjetos1.expressao.leftExpression.Id;
import plp.orientadaObjetos1.expressao.unaria.ExpUnaria;
import plp.orientadaObjetos1.expressao.valor.Valor;
import plp.orientadaObjetos1.expressao.valor.ValorRef;
import plp.orientadaObjetos1.expressao.valor.ValorString;
import plp.orientadaObjetos1.memoria.AmbienteCompilacaoOO1;
import plp.orientadaObjetos1.memoria.AmbienteExecucaoOO1;
import plp.orientadaObjetos1.util.Tipo;
import plp.orientadaObjetos1.util.TipoClasse;
import plp.orientadaObjetos1.util.TipoPrimitivo;
import plp.orientadaObjetos2.ambiente.Classe;
import plp.orientadaObjetos2.ambiente.Nomes;
import plp.orientadaObjetos2.memoria.AmbienteExecucaoOO2;
import plp.orientadaObjetos2.memoria.ObjetoNativo;

public class GetClasse extends ExpUnaria {

	private static final Id ID_CLASSE = new Id(Nomes.CLASSE_CLASSE);
	private static final TipoClasse TIPO_CLASSE = new TipoClasse(ID_CLASSE);


	public GetClasse(Expressao exp) {
		super(exp, "getClasse(" + exp + ")");
	}

	@Override
	public Valor avaliar(AmbienteExecucaoOO1 ambiente)
			throws VariavelNaoDeclaradaException, VariavelJaDeclaradaException,
			ObjetoNaoDeclaradoException, ClasseNaoDeclaradaException {
		ValorRef ref;
		ValorString valorString = (ValorString) this.getExp().avaliar(ambiente);
		AmbienteExecucaoOO2 ambienteOO2 = (AmbienteExecucaoOO2) ambiente;
		Classe classe = new Classe(valorString.valor());		
		ref = ambienteOO2.getProxRef();
		try {
			ambienteOO2.mapObjeto(ref, new ObjetoNativo(ID_CLASSE, classe));
		} catch (ObjetoJaDeclaradoException e) {
			// Vazio.
		}
		return ref;
	}


	@Override
	public Tipo getTipo(AmbienteCompilacaoOO1 ambiente)
			throws VariavelNaoDeclaradaException, ClasseNaoDeclaradaException {
		return TIPO_CLASSE;
	}

	@Override
	public boolean checaTipo(AmbienteCompilacaoOO1 ambiente)
			throws VariavelNaoDeclaradaException,
			VariavelNaoDeclaradaException, ClasseNaoDeclaradaException {
		return super.checaTipo(ambiente) &&
				this.getExp().getTipo(ambiente).equals(TipoPrimitivo.TIPO_STRING);
	}
}
